from bigchaindb import Bigchain
from bigchaindb.common import crypto
from bigchaindb.models import Transaction
from bigchaindb.common.transaction import Output, Input
from bigchaindb.common.exceptions import (KeypairMismatchException,
                                          InvalidHash, InvalidSignature,
                                          AmountError, AssetIdMismatch)
b = Bigchain()
import time
bob = crypto.generate_key_pair()
print(bob[0])
print(bob[1])

blackhole_key = "AL462P9Tw3woMTjLeKuera3iMGydb7THAMdQBxyjLjcD"

bank_priv_key = "AcemH87Y5uA8atHxowdKptqahC6K5vAp8RLH2gwH4MbZ"
bank_pub_key = "CzK7LQoBvTMa7yMn6LABiZVai88meAerZy33suuuNpJC"
super_priv_key = "Qtac1Raj3cfmegCzkbcxXroPvHvTMuX32dCV7PG334P"
super_pub_key = "9EbKMgcjqriwCiXRrx2U1VAh163WfAHFRvqwRJ8XSod8"

A_priv_key = "BGEDxHBcwV9WcAiX8P1Aksghey5r7W5TXXRgarhTCfmt"
A_pub_key = "5KFPkRfWp8PkRLP1tppJkSzqNi7WzTiMRjG242SBAyEH"

B_priv_key = "B8ozQ65chPmSeoWdTjjYX3Mbogd7D2n5rVnpJrvqVwv1"
B_pub_key = "CQF5tkL9kTM5X9F2ZeBAk879nUDL7JjEeBR66LStD5Kp"

asset = {'type':'money RMB'}

print("test case 1: A's asset $1 transfered by A's private key (single condition)")
tx = Transaction.create([bank_pub_key], [([A_pub_key], 1)], asset = asset, metadata = {'time':time.time()})
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 1)], tx.id, metadata = {'time':time.time()})
tx = tx.sign([A_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
print("test case 1: pass")

print("test case 2: A's asset $100 transfered by A's private key (single condition)")
tx = Transaction.create([bank_pub_key], [([A_pub_key], 100)], asset = asset, metadata = {'time':time.time()})
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 100)], tx.id, metadata = {'time':time.time()})
tx = tx.sign([A_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
print("test case 2: pass")

print("test case 3: A's asset $100 can't be transfered by B's private key (single condition)")
tx = Transaction.create([bank_pub_key], [([A_pub_key], 100)], asset = asset, metadata = {'time':time.time()})
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 100)], tx.id, metadata = {'time':time.time()})
try:
    tx = tx.sign([B_priv_key])
except KeypairMismatchException:
    print("test case 3: pass")

print("test case 4: A's asset $100 can't be transfered by A's wrong sig (single condition)")
tx = Transaction.create([bank_pub_key], [([A_pub_key], 100)], asset = asset, metadata = {'time':time.time()})
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 100)], tx.id, metadata = {'time':time.time()})
tx = tx.sign([A_priv_key])
tx.inputs[0].fulfillment.signature = b'g3L|\xd8\x86\xbb%\xa4\xaaZ\xac\xae\x95\x00\x8f\x93\x06\xa9T\xc6se\xbd\x86\xec\xc8S\x9e\x8f%O\t#Uk\xf4\x8e\xfdzQ\x1f\xbd`\x99\xe7\x8d5\x1c\xb9)\xf0_Jf\xf1\xe3\x8c\xf19\x03{\xc3\x00'
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == None:
        break
print("test case 4: pass")

print("test case 5: A's asset $100 transfered by A's private key (threshold condition)")
tx = Transaction.create([bank_pub_key], [([A_pub_key], 100)], asset = asset, metadata = {'time':time.time()})
tx.outputs[0] = Output.generate([A_pub_key, bank_pub_key, super_pub_key], 100)
tx.outputs[0].public_keys = [A_pub_key]
output = tx.outputs[0].to_dict()
output['condition']['details']['threshold'] = 2
for i in range(len(output['condition']['details']['subfulfillments'])):
    if output['condition']['details']['subfulfillments'][i]['public_key'] == tx.outputs[0].public_keys[0]:
        output['condition']['details']['subfulfillments'][i]['weight'] = output['condition']['details']['threshold']
tx.outputs[0] = Output.from_dict(output)
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 100)], tx.id, metadata = {'time':time.time()})
tx = tx.sign([A_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
print("test case 5: pass")

print("test case 6: A's asset $100 transfered by bank and super's private key (threshold condition)")
tx = Transaction.create([bank_pub_key], [([A_pub_key], 100)], asset = asset, metadata = {'time':time.time()})
tx.outputs[0] = Output.generate([A_pub_key, bank_pub_key, super_pub_key], 100)
tx.outputs[0].public_keys = [A_pub_key]
output = tx.outputs[0].to_dict()
output['condition']['details']['threshold'] = 2
for i in range(len(output['condition']['details']['subfulfillments'])):
    if output['condition']['details']['subfulfillments'][i]['public_key'] == tx.outputs[0].public_keys[0]:
        output['condition']['details']['subfulfillments'][i]['weight'] = output['condition']['details']['threshold']
tx.outputs[0] = Output.from_dict(output)
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 100)], tx.id, metadata = {'time':time.time()})
tx = tx.sign([bank_priv_key, super_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
print("test case 6: pass")

print("test case 7: A's asset $100 can't be transfered by one bank's private key (threshold condition)")
tx = Transaction.create([bank_pub_key], [([A_pub_key], 100)], asset = asset, metadata = {'time':time.time()})
tx.outputs[0] = Output.generate([A_pub_key, bank_pub_key, super_pub_key], 100)
tx.outputs[0].public_keys = [A_pub_key]
output = tx.outputs[0].to_dict()
output['condition']['details']['threshold'] = 2
for i in range(len(output['condition']['details']['subfulfillments'])):
    if output['condition']['details']['subfulfillments'][i]['public_key'] == tx.outputs[0].public_keys[0]:
        output['condition']['details']['subfulfillments'][i]['weight'] = output['condition']['details']['threshold']
tx.outputs[0] = Output.from_dict(output)
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 100)], tx.id, metadata = {'time':time.time()})
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == None:
        break
print("test case 7: pass")

print("test case 8: A's asset $100 can't be transfered by B's private key if condition is modified (threshold condition)")
tx = Transaction.create([bank_pub_key], [([A_pub_key], 100)], asset = asset, metadata = {'time':time.time()})
tx.outputs[0] = Output.generate([A_pub_key, bank_pub_key, super_pub_key], 100)
tx.outputs[0].public_keys = [A_pub_key]
output = tx.outputs[0].to_dict()
output['condition']['details']['threshold'] = 2
for i in range(len(output['condition']['details']['subfulfillments'])):
    if output['condition']['details']['subfulfillments'][i]['public_key'] == tx.outputs[0].public_keys[0]:
        output['condition']['details']['subfulfillments'][i]['weight'] = output['condition']['details']['threshold']
tx.outputs[0] = Output.from_dict(output)
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
inputs = transfer_inputs[0].to_dict()
inputs["fulfillment"]["subfulfillments"][0]["public_key"] = B_pub_key
inputs["owners_before"] = [B_pub_key]
transfer_inputs[0] = Input.from_dict(inputs)
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 100)], tx.id, metadata = {'time':time.time()})
tx = tx.sign([B_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == None:
        break
print("test case 8: pass")

print("test case 9: A's asset $100 can't be transfered by A's wrong sig (threshold condition)")
tx = Transaction.create([bank_pub_key], [([A_pub_key], 100)], asset = asset, metadata = {'time':time.time()})
tx.outputs[0] = Output.generate([A_pub_key, bank_pub_key, super_pub_key], 100)
tx.outputs[0].public_keys = [A_pub_key]
output = tx.outputs[0].to_dict()
output['condition']['details']['threshold'] = 2
for i in range(len(output['condition']['details']['subfulfillments'])):
    if output['condition']['details']['subfulfillments'][i]['public_key'] == tx.outputs[0].public_keys[0]:
        output['condition']['details']['subfulfillments'][i]['weight'] = output['condition']['details']['threshold']
tx.outputs[0] = Output.from_dict(output)
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 100)], tx.id, metadata = {'time':time.time()})
tx = tx.sign([A_priv_key])
tx.inputs[0].fulfillment.subconditions[0]['body'].signature = b'g3L|\xd8\x86\xbb%\xa4\xaaZ\xac\xae\x95\x00\x8f\x93\x06\xa9T\xc6se\xbd\x86\xec\xc8S\x9e\x8f%O\t#Uk\xf4\x8e\xfdzQ\x1f\xbd`\x99\xe7\x8d5\x1c\xb9)\xf0_Jf\xf1\xe3\x8c\xf19\x03{\xc3\x00'
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == None:
        break
print("test case 9: pass")

print("test case 10: A's asset $100, A pays to B $10, B pays to A $5 (threshold condition)")
tx = Transaction.create([bank_pub_key], [([A_pub_key], 100)], asset = asset, metadata = {'time':time.time()})
tx = tx.sign([bank_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 10), ([A_pub_key], 90)], tx.id, metadata = {'time':time.time()})
tx = tx.sign([A_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
transfer_inputs = tx.to_inputs()
for input in transfer_inputs:
    if input.owners_before[0] == B_pub_key:
        transfer_inputs = [input]
tx = Transaction.transfer(transfer_inputs, [([B_pub_key], 5), ([A_pub_key], 5)], tx.asset['id'], metadata = {'time':time.time()})
tx = tx.sign([B_priv_key])
b.write_transaction(tx)
while True:
    time.sleep(1)
    temp, status = b.get_transaction(tx.id, include_status=True)
    if status == b.TX_VALID:
        break
print("test case 10: pass")